# $Id: query.py 7557b5d4d82b 2012/12/02 09:07:16 pgurumur $
# Copyright (c) 2009 Prabhu Gurumurthy  <pgurumur@gmail.com>
# 
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

__version__ = "$Revision: 7557b5d4d82b $"
__author__ = "$Author: pgurumur $"

from django.db import connection, transaction
from djanet.db import netdb, ssndb
from djanet.lib import exception, ip

def returnAsDict(cursor):
   "Returns all rows from a cursor as a dict"
   desc = cursor.description
   return [ dict(zip([col[0] for col in desc], row))
         for row in cursor.fetchall()]

def SQLRaw(SQLQuery):
   retval = None
   if SQLQuery:
      cursor = connection.cursor()
      cursor.execute(SQLQuery)
      transaction.commit_unless_managed()
      retval = returnAsDict(cursor)

   return retval

def GetAllEntities():
   retval = [ix for ix in netdb.Entity.objects.all().values_list('id', 'name')]
   retval.insert(0, (0, "None"))
   return retval

def GetDevice(Address):
   retval = None
   if Address:
      ipobj = netdb.Ipblock.objects.filter(
            address = int(Address)).all()
      if len(ipobj):
         device = netdb.Device.objects.filter(snmp_target = ipobj[0].id).all()
         if len(device):
            retval = device[0]

   return retval

def ValidIPv6(Address):
   retval = None
   temp = None
   length = Address.length

   for ix in netdb.Ipblock.objects.filter(
         prefix__lte = length, version = 6).all():
      if Address in ix.ip:
         retval = False
         break

   for ix in netdb.Ipblock.objects.filter(
         prefix__gt = length, version = 6).all():
      if ix.ip in Address:
         retval = False
         break

   for ix in ssndb.Ipv6Prefix.objects.using('ssn').all():
      if Address in ix.ip:
         retval = False
         break
      elif ix.ip in Address:
         retval = False
         break

   if retval is None:
      try:
         temp = netdb.Ipblock.objects.filter(address = int(Address)).values()[0]
      except IndexError, message:
         retval = True
      else:
         retval = False

      if retval:
         temp = ssndb.Ipv6Prefix.objects.using('ssn').filter(
               prefix = str(Address)).values()
         if temp:
            retval = False

   return retval

def get_network(version = 4):
   obj = IPQuery()
   return obj.network(version)

def get_devices():
   obj = DeviceQuery()
   return obj.GetAllDevices()

class IPQuery(object):
   def __init__(self):
      self._err = exception.QueryError
      self._objects = netdb.Ipblock.objects
      self._ipv4MaxLength = 32
      self._ipv6MazLength = 128

   def _error(self, Message):
      if Message:
         raise exception.QueryError, str(Message)

   def _ip(self, address, Prefix = 0, Version = 0):
      prefix = 0
      version = 0
      try:
         if Prefix:
            prefix = int(Prefix)

         if Version:
            version = int(Version)
      except ValueError, message:
         self._error(message)

      retval = None
      temp = None
      try:
         if isinstance(address, (str, unicode)):
            temp = ip.ip(str(Address))
            address = int(temp)
            if not (prefix and version):
               prefix = len(temp)
               version = temp.version()
            elif not prefix:
               prefix = len(temp)
            elif not version:
               version = temp.version()

         if isinstance(address, (int, long)):
            retval = ip.ip(address, prefix = prefix, version = version)
      except exception.IPError, message:
         raise exception.QueryError, message

      return retval

   def network(self, version = 4):
      retval = []
      count = 0

      prefixMatch = 0
      if version == 4:
         prefixMatch = self._ipv4MaxLength
      elif version == 6:
         prefixMatch = self._ipv6MaxLength

      for obj in self._objects.filter(
            version__exact = version, prefix__lt = prefixMatch).values_list(
                  'id', 'address', 'prefix', 'version'):
         retval.append((int(obj[0]), self._ip(
            int(obj[1]), int(obj[2]), int(obj[3]))))

      return retval

   def GetObject(self, Address, **Keywords):
      retval = None
      prefix = None
      version = None
      getid = False

      if "prefix" in Keywords:
         prefix = Keywords["prefix"]

      if "version" in Keywords:
         version = Keywords["version"]

      if "getid" in Keywords:
         getid = bool(Keywords["getid"])

      temp = self._ip(Address, prefix, version)
      if temp:
         if getid:
            retval = self._objects.filter(address__exact = int(temp),
                  prefix__exact = len(temp),
                  version = temp.version()).values_list('id')
         else:
            retval = self._objects.filter(address__exact = int(temp),
                  prefix__exact = len(temp), version = temp.version())

         if len(retval) == 1:
            retval = retval[0]

      return retval

   def GetId(self, Address, **keywords):
      keywords["getid"] = True
      return self.GetObject(Address, **keywords)

   def GetIP(self, Id):
      retval = None
      objid = 0
      try:
         objid = int(Id)
      except ValueError, message:
         raise ValueError, message
      else:
         listval = self._objects.filter(id__exact = objid).values_list(
               'address', 'prefix', 'version')[0]
         retval = self._ip(int(listval[0]), listval[1], listval[2])

      return retval

class DeviceQuery(object):
   def __init__(self):
      self._err = exception.QueryError()
      self._objects = netdb.Device.objects

   def GetAllDevices(self):
      retval = []
      for (devid, nameid, siteid) in self._objects.values_list(
            'id', 'name', 'site'):
         name = netdb.Rr.objects.filter(
               id__exact = int(nameid)).values_list('name')[0]
         if siteid:
            site = netdb.Site.objects.filter(
                  id__exact = int(siteid)).values_list('name')[0]
            devname = "%s : %s" %(str(site[0]), str(name[0]))
            retval.append((devid, devname))

      return retval

   def GetObject(self, Id):
      retval = None
      objid = 0
      try:
         objid = int(Id)
      except ValueError, message:
         raise ValueError, message
      else:
         retval = self._objects.filter(id__exact = objid)[0]

      return retval

   def GetAddressId(self, Id):
      retval = None
      objid = 0
      try:
         objid = int(Id)
      except ValueError, message:
         raise ValueError, message
      else:
         retval = self._objects.filter(id__exact = Id).values_list(
            'snmp_target')[0][0]

      return retval

class ModelQuery(object):
   def __init__(self):
      self._err = exception.QueryError()
      self._ip = IPQuery()
      self._device = DeviceQuery()

   def GetAllNetwork(self, Version):
      return self._ip.network(Version)

   def GetAllDevices(self):
      return self._device.GetAllDevices()

   def GetDeviceObject(self, Id):
      return self._device.GetObject(Id)

   def GetDeviceId(self, Device):
      return int(Device.objects.values_list('id')[0][0])

   def GetDeviceIP(self, Id):
      return self._ip.GetIP(self._device.GetAddressId(Id))

   def GetSites(self, Name):
      retval = None
      if Name and isinstance(Name, str):
         retval = netdb.Site.objects.filter(name__exact = Name)[0]
      else:
         retval = []
         count = 0
         for sites in netdb.Site.objects.values('name'):
            count += 1
            retval.append((count, sites['name']))

      return retval

   def GetInterfaceList(self, Name, Site):
      retval = []
      for intfs in netdb.Interface.objects.filter(
            self.GetDeviceObject(Name).values_list('id')[0][0]):
         retval.append(intfs[0])

      return retval

   def GetAllDeviceNames(self, Zone = False):
      retval = []
      for values in netdb.Device.objects.values_list('name'):
         (name, site) = netdb.Rr.objects.filter(
               id__exact = int(values[0])).values_list('name', 'zone')[0]
         zone = netdb.Zone.objects.filter(
               id__exact = int(zoneid)).values_list('mname')[0]
         sysname = None
         if Zone:
            sysname = "%s.%s" %(name, zone[0])
         else:
            sysname = "%s" %name

         retval.append(sysname)

      return retval
